package cn.jasonone.jasonfx.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import cn.jasonone.jasonfx.exception.JasonFxException;

/**
 * 反射工具类
 * 
 * @author Jason
 * @date: 2020-01-12 15:34
 */
public class ClassUtil {
	private static final String CGLIB_PROXY_TAG = "$$EnhancerByCGLIB$$";

	/**
	 * 检测是否为cglib代理
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isProxy(Class<?> type) {
		if (type == null)
			return false;
		if (type.getName().contains(CGLIB_PROXY_TAG)) {
			return true;
		}
		return false;
	}

	/**
	 * 获取原始类型
	 * 
	 * @param type 类
	 * @return Class
	 */
	public static Class<?> getClass(Class<?> type) {
		if (isProxy(type)) {
			return getClass(type.getSuperclass());
		}
		return type;
	}

	/**
	 * 实例化指定类,无法实例化带有基本数据类型的构造函数
	 * 
	 * @param <T>  类型
	 * @param type 类
	 * @return 实例
	 */
	public static <T> T newInstance(Class<T> type, Object... args) {
		try {
			Class<?>[] parameterTypes = new Class<?>[args.length];
			for (int i = 0; i < args.length; i++) {
				parameterTypes[i] = getClass(args[i].getClass());
			}
			Constructor<T> constructor=null;
			Constructor<T>[] constructors = (Constructor<T>[]) type.getConstructors();
			for (Constructor<T> constructor2 : constructors) {
				Class<?>[] types = constructor2.getParameterTypes();
				constructor=constructor2;
				for (int i = 0; i < types.length; i++) {
					if(!types[i].isAssignableFrom(parameterTypes[i])) {
						constructor=null;
						break;
					}
				}
			}
			if(constructor==null) {
				throw new JasonFxException("无法实例化["+type.getName()+"],请检查构造["+type.getSimpleName()+"("+Arrays.toString(parameterTypes)+")]是否存在");
			}
			return constructor.newInstance(args);
		} catch (InstantiationException | IllegalAccessException | SecurityException
				| IllegalArgumentException | InvocationTargetException e) {
			throw ExceptionUtil.wrapJasonFxException(e);
		}
	}

	/**
	 * 获取指定类的字段列表
	 * 
	 * @param type 类
	 * @return 字段集合
	 */
	public static List<Field> getFields(Class<?> type) {
		return getFields(type, null);
	}

	/**
	 * 清除集合中的常量
	 * 
	 * @param fields 字段集合
	 */
	public static void clearFieldFinal(List<Field> fields) {
		fields.removeIf(f -> isFinal(f));
	}

	/**
	 * 获取指定类的字段列表
	 * 
	 * @param type          类
	 * @param endSuperClass 获取字段的最终父类
	 * @return 字段集合
	 */
	public static List<Field> getFields(Class<?> type, Class<?> endSuperClass) {
		List<Field> list = new ArrayList<>();
		if (type.getSuperclass() != null) {
			if (endSuperClass == null
					|| (endSuperClass != null && endSuperClass.isAssignableFrom(type.getSuperclass()))) {
				list.addAll(getFields(type.getSuperclass(), endSuperClass));
			}
		}
		Field[] fields = type.getDeclaredFields();
		if (fields != null && fields.length > 0) {
			list.addAll(Arrays.asList(fields));
		}
		return list.isEmpty() ? Collections.emptyList() : list;
	}

	/**
	 * 是否为抽象类
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isAbstract(Class<?> type) {
		return Modifier.isAbstract(type.getModifiers());
	}

	/**
	 * 是否为抽象方法
	 * 
	 * @param method 方法
	 * @return boolean
	 */
	public static boolean isAbstract(Method method) {
		return Modifier.isAbstract(method.getModifiers());
	}

	/**
	 * 检测是否被final修饰
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isFinal(Class<?> type) {
		return Modifier.isFinal(type.getModifiers());
	}

	/**
	 * 检测是否被final修饰
	 * 
	 * @param field 字段
	 * @return boolean
	 */
	public static boolean isFinal(Field field) {
		return Modifier.isFinal(field.getModifiers());
	}

	/**
	 * 检测是否被final修饰
	 * 
	 * @param method 方法
	 * @return boolean
	 */
	public static boolean isFinal(Method method) {
		return Modifier.isFinal(method.getModifiers());
	}

	/**
	 * 是否是接口
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isInterface(Class<?> type) {
		return type.isInterface();
	}

	/**
	 * 是否是集合
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isCollection(Class<?> type) {
		return Collection.class.isAssignableFrom(type);
	}

	/**
	 * 是否是数组
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isArray(Class<?> type) {
		return type.isArray();
	}

	/**
	 * 是否是枚举
	 * 
	 * @param type 类
	 * @return boolean
	 */
	public static boolean isEnum(Class<?> type) {
		return type.isEnum();
	}

	/**
	 * 给实例的指定字段设置值
	 * 
	 * @param field 字段对象
	 * @param obj   实例
	 * @param value 值
	 */
	public static void set(Field field, Object obj, Object value) {
		if (isFinal(field)) {
			return;
		}
		field.setAccessible(true);
		try {
			field.set(obj, value);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw ExceptionUtil.wrapJasonFxException(e);
		}
	}

	/**
	 * 获取实例中指定字段的值
	 * 
	 * @param <T>   值的类型
	 * @param field 字段
	 * @param obj   实例
	 * @return 值
	 */
	@SuppressWarnings("unchecked")
	public static <T> T get(Field field, Object obj) {
		field.setAccessible(true);
		try {
			return (T) field.get(obj);
		} catch (IllegalArgumentException | IllegalAccessException e) {
			throw ExceptionUtil.wrapJasonFxException(e);
		}
	}

	/**
	 * 拷贝俩个实例的值
	 * 
	 * @param source 源对象
	 * @param taget  目标对象
	 */
	public static <T> void copyFieldValues(T source, T taget) {
		List<Field> fields = getFields(source.getClass());
		for (Field field : fields) {
			set(field, taget, get(field, source));
		}
	}

	/**
	 * 获得字段的泛型参数列表
	 * 
	 * @param <T>   返回值类型
	 * @param field 字段对象
	 * @return 泛型实际类型列表
	 */
	@SuppressWarnings("unchecked")
	public static <T extends Type> List<T> getGenericType(Field field) {
		if (field == null) {
			return null;
		}
		ParameterizedType pt = (ParameterizedType) field.getGenericType();
		return (List<T>) Arrays.asList(pt.getActualTypeArguments());
	}
}
